﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Authentication.JwtBearer;

namespace Util
{
    public static class AuthorizationSetup
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void AddAuthorizationSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));

            // 1【授权】、这个和上边的异曲同工，好处就是不用在controller中，写多个 roles 。
            // 然后这么写 [Authorize(Policy = "Admin")]
            //services.AddAuthorization(options =>
            //{
            //    options.AddPolicy("User", policy => policy.RequireRole("User").Build());
            //    options.AddPolicy("VistManagerOrAdministrator", policy => policy.RequireRole("Administrator", "VistManager"));
            //});

            //读取配置文件
            var symmetricKeyAsBase64 = AppSettingHelper.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var Issuer = AppSettingHelper.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            var Audience = AppSettingHelper.app(new string[] { "AppSettings", "JwtSetting", "Audience" });
            //string audiences = string.Join("," ,AppSettingHelper.GetSetting<List<string>>("AppSettings:JwtSetting:Audience"));
            //var keyId = "your_key_id"; // 密钥ID 

            // 令牌验证参数
            var tokenValidationParameters = new MyTokenValidationParameters
            {
                //KeyId = keyId, // 设置密钥ID  
                ValidateIssuerSigningKey = true,//是否验证签名,不验证的画可以篡改数据，不安全
                IssuerSigningKey = signingKey,//解密的密钥
                ValidateIssuer = true,//是否验证发行人，就是验证载荷中的Iss是否对应ValidIssuer参数
                ValidIssuer = Issuer,//发行人
                ValidateAudience = true,//是否验证订阅人，就是验证载荷中的Aud是否对应ValidAudience参数
                ValidAudience = Audience,//订阅人
                //ValidAudience = audiences,
                ValidateLifetime = true,//是否验证过期时间，过期了就拒绝访问
                ClockSkew = TimeSpan.Zero,//这个是缓冲过期时间，也就是说，即使我们配置了过期时间，这里也要考虑进去，过期时间+缓冲，默认好像是7分钟，你可以直接设置为0
                RequireExpirationTime = true,
            };

            services.AddAuthentication("Bearer")
            .AddJwtBearer(o =>
            {
                o.TokenValidationParameters = tokenValidationParameters;
                o.Events = new JwtBearerEvents()
                {
                    OnMessageReceived = context =>
                    {
                        context.Token = context.Request.Query["access_token"];
                        return Task.CompletedTask;
                    },
                    OnAuthenticationFailed = context =>
                    {
                        // 如果过期，则把<是否过期>添加到，返回头信息中
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    }
                };
            });
        }
    }
}
